#include <iostream>
#include <memory>
#include <string>

class Fruit
{
public:
    virtual void name() = 0;
};

class Apple : public Fruit
{
public:
    void name() override
    {
        std::cout << "i am a apple" << std::endl;
    }
};

class Pineapple : public Fruit
{
public:
    void name() override
    {
        std::cout << "i am a pineapple" << std::endl;
    }
};

class Animal
{
public:
    virtual void voice() = 0;
};

class Dragon : public Animal
{
public:
    void voice() override
    {
        std::cout << "恶龙咆哮" << std::endl;
    }
};

class Wolf : public Animal
{
public:
    void voice() override
    {
        std::cout << "我一定会回来的" << std::endl;
    }
};

// class FruitFactory
// {
// public:
//     static std::shared_ptr<Fruit> create(const std::string& name)
//     {
//         if(name == "apple")
//             return std::make_shared<Apple>();
//         else if(name == "pineapple")
//             return std::make_shared<Pineapple>();
//         return std::shared_ptr<Fruit>();            // 此处不能使用make_shared，不然参数包传递会出错
//     }
// };

// int main()
// {
//     std::shared_ptr<Fruit> fruit = FruitFactory::create("apple");       // 使用静态函数，无需创建FruitFactory对象
//     fruit->name();
//     fruit.reset();
//     fruit = FruitFactory::create("pineapple");
//     fruit->name();
//     return 0;
// }


// 工厂方法

// class Factory
// {
// public:
//     virtual std::shared_ptr<Fruit> create() = 0;
// };

// class AppleFactory : public Factory
// {
// public:
//     std::shared_ptr<Fruit> create()
//     {
//         return std::make_shared<Apple>();
//     }
// };

// class PineappleFactory : public Factory
// {
// public:
//     std::shared_ptr<Fruit> create()
//     {
//         return std::make_shared<Pineapple>();
//     }
// };

// int main()
// {
//     std::shared_ptr<Factory> fruitFactory(new AppleFactory());
//     std::shared_ptr<Fruit> fruit = fruitFactory->create();
//     fruit->name();
//     fruitFactory.reset(new PineappleFactory());
//     fruit = fruitFactory->create();
//     fruit->name();

//     return 0;
// }


// 抽象工厂

class Factory
{
public:
    virtual std::shared_ptr<Fruit> getFruit(const std::string& name) = 0;
    virtual std::shared_ptr<Animal> getAnimal(const std::string& name) = 0;
};

class FruitFactory : public Factory
{
public:
    std::shared_ptr<Fruit> getFruit(const std::string& name) override
    {
        if(name == "apple")
            return std::make_shared<Apple>();
        else if(name == "pineapple")
            return std::make_shared<Pineapple>();
        return std::shared_ptr<Fruit>();        // 需用shared_ptr
    }

    std::shared_ptr<Animal> getAnimal(const std::string& name)  override
    {
        return std::shared_ptr<Animal>();        // 需用shared_ptr
    }
};

class AnimalFactory : public Factory
{
public:
    std::shared_ptr<Fruit> getFruit(const std::string& name)  override
    {
        return std::shared_ptr<Fruit>();
    }

    std::shared_ptr<Animal> getAnimal(const std::string& name) override
    {
        if(name == "dragon")
            return std::make_shared<Dragon>();
        else if(name == "wolf")
            return std::make_shared<Wolf>();
        return std::shared_ptr<Animal>();
    }
};

class FactoryProducer
{
public:
    static std::shared_ptr<Factory> getFactory(const std::string& name)     // 可以声明为静态，这样调用时就不用创建对象
    {
        if(name == "fruit")
            return std::make_shared<FruitFactory>();
        else if(name == "animal")
            return std::make_shared<AnimalFactory>();
        return std::shared_ptr<Factory>();
    }
};


int main()
{
    // std::shared_ptr<FactoryProducer> factoryProducer(new FactoryProducer());
    // std::shared_ptr<Factory> factory = factoryProducer->getFactory("fruit");
    
    std::shared_ptr<Factory> factory = FactoryProducer::getFactory("fruit");
    std::shared_ptr<Fruit> fruit = factory->getFruit("apple");
    fruit->name();
    fruit.reset();
    fruit = factory->getFruit("pineapple");
    fruit->name();
    std::cout << "\n";

    // factory = factoryProducer->getFactory("animal");
    factory = FactoryProducer::getFactory("animal");
    std::shared_ptr<Animal> animal = factory->getAnimal("dragon");
    animal->voice();
    animal.reset();
    animal = factory->getAnimal("wolf");
    animal->voice();

    return 0;
}